Setup

library(phyloseq)
library(vegan)
Loading required package: permute
Loading required package: lattice
This is vegan 2.4-0
library(ade4)

Attaching package: ‘ade4’

The following object is masked from ‘package:vegan’:

    cca
library(ggplot2)
library(ggthemes)
library(stringr)
library(tidyr)
library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union

 

  1. Load the image for Nature 488, pp. 621-626 dataset.
load("../data/STAT.rdata")

 

  1. Use distance() function to compute JSD distance of the normalized microbiome data.
dist_jsd <- phyloseq::distance(phy, method = distanceMethodList$JSD)
str(dist_jsd)
Class 'dist'  atomic [1:4560] 0.1539 0.0959 0.0971 0.0817 0.1112 ...
  ..- attr(*, "Labels")= chr [1:96] "cecal_C1" "cecal_C10" "cecal_C2" "cecal_C3" ...
  ..- attr(*, "Size")= int 96
  ..- attr(*, "call")= language as.dist.default(m = DistMat)
  ..- attr(*, "Diag")= logi FALSE
  ..- attr(*, "Upper")= logi FALSE
  1. Compute hierarchical clustering using Single, Average, and Complete linkage.
plot(hclust(dist_jsd, "single"))

hclust(dist_jsd, "average") %>% 
    plot()

hclust(dist_jsd, "complete") %>% 
    plot()

  1. Plot the dendrograms from 3.

  2. Use rect.hclust function to produce best discrete clusters from the dendrograms.

hclust_single = hclust(dist_jsd, "single")
plot(hclust_single)
rect.hclust(hclust_single, k = 3)

hclust_average = hclust(dist_jsd, "average")
plot(hclust_average)
rect.hclust(hclust_average, k = 3)

hclust_complete = hclust(dist_jsd, "complete")
plot(hclust_complete)
rect.hclust(hclust_complete, k = 3)

  1. Compute and plot cophenetic distance against the JSD distances computed in 2 for each of the hierarchical clusterings in 3.
plot(cophenetic(hclust_single), dist_jsd)

plot(dist_jsd, cophenetic(hclust_average))

plot(dist_jsd, cophenetic(hclust_complete))

  1. How well do the cophenetic distances represent the original distances? Compute correlations.

  2. Use Partitioning around Medoids, pam, to cluster the JSD distances into two clusters.

pam_jsd <- cluster::pam(dist_jsd, 2)
str(pam_jsd)
List of 9
 $ medoids   : chr [1:2] "cecal_P3" "fecal_C2"
 $ id.med    : int [1:2] 14 53
 $ clustering: Named int [1:96] 1 1 1 1 1 1 1 1 1 1 ...
  ..- attr(*, "names")= chr [1:96] "cecal_C1" "cecal_C10" "cecal_C2" "cecal_C3" ...
 $ objective : Named num [1:2] 0.133 0.123
  ..- attr(*, "names")= chr [1:2] "build" "swap"
 $ isolation : Factor w/ 3 levels "no","L","L*": 1 1
  ..- attr(*, "names")= chr [1:2] "1" "2"
 $ clusinfo  : num [1:2, 1:5] 49 47 0.372 0.275 0.129 ...
  ..- attr(*, "dimnames")=List of 2
  .. ..$ : NULL
  .. ..$ : chr [1:5] "size" "max_diss" "av_diss" "diameter" ...
 $ silinfo   :List of 3
  ..$ widths         : num [1:96, 1:3] 1 1 1 1 1 1 1 1 1 1 ...
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ : chr [1:96] "cecal_V10" "cecal_VP7" "cecal_VP8" "cecal_C10" ...
  .. .. ..$ : chr [1:3] "cluster" "neighbor" "sil_width"
  ..$ clus.avg.widths: num [1:2] 0.377 0.424
  ..$ avg.width      : num 0.4
 $ diss      : NULL
 $ call      : language cluster::pam(x = dist_jsd, k = 2)
 - attr(*, "class")= chr [1:2] "pam" "partition"
# plot(pam_jsd)
  1. Test for association of the clusters with the Treatment and Location and variables.
table(sample_data(phy)$Treatment, pam_jsd$clustering)
    
      1  2
  C  10 10
  P  10  9
  T  10  9
  V  10 10
  VP  9  9
table(sample_data(phy)$Location, pam_jsd$clustering)
       
         1  2
  cecal 49  1
  fecal  0 46
library(clusterSim)
cluster.tr = table(sample_data(phy)$Treatment, pam_jsd$clustering)
chisq.test(cluster.tr)

    Pearson's Chi-squared test

data:  cluster.tr
X-squared = 0.063624, df = 4, p-value = 0.9995
cluster.loc = table(sample_data(phy)$Location, pam_jsd$clustering)
chisq.test(cluster.loc)

    Pearson's Chi-squared test with Yates' continuity correction

data:  cluster.loc
X-squared = 88.198, df = 1, p-value < 2.2e-16
  1. Compute the gap statistic plot to determine the optimal number of clusters for these data.
pam1 <- function(x,k) list(cluster = pam(as.dist(x),k, cluster.only=TRUE))
gsPam1 <- clusGap(as.matrix(dist_jsd), FUN = pam1, K.max = 20, B = 100)
Clustering k = 1,2,..., K.max (= 20): .. done
Bootstrapping, b = 1,2,..., B (= 100)  [one "." per sample]:
.................................................. 50 
.................................................. 100 
par(mfrow=c(1,1))
plot(gsPam1)

gsPam1$Tab %>% 
    as.data.frame() %>% 
    ggplot(aes(x = 1:20, y = gap)) +
    geom_line() +
    geom_errorbar(aes(ymin = gap - 2*SE.sim, ymax = gap + 2*SE.sim), 
                  colour = "red") +
    geom_errorbar(aes(ymin = gap - SE.sim, ymax = gap + SE.sim), 
                  colour = "black", linetype = "dashed")

  1. Install and load the following packages: “randomForest”, “kernlab”, “ROCR”.

  2. Use the provided 6-fold cross validation functions (svm.kfoldAUC and rf.kfoldAUC) to estimate prediction accuracy in 100 repetitions using Phylum level data for:

A. Location; B. Antibiotic vs. Control within fecal samples; C. Antibiotic vs. Control within cecal samples.

Alternatively, use the “caret” package to accomplish the same.

source("../labs/Lab-07-Clustering-and-Classification/CV_protocols.R")

Attaching package: ‘kernlab’

The following object is masked from ‘package:ggplot2’:

    alpha

The following object is masked from ‘package:permute’:

    how

Loading required package: gplots

Attaching package: ‘gplots’

The following object is masked from ‘package:stats’:

    lowess

randomForest 4.6-12
Type rfNews() to see new features/changes/bug fixes.

Attaching package: ‘randomForest’

The following object is masked from ‘package:dplyr’:

    combine

The following object is masked from ‘package:ggplot2’:

    margin
runInParallel = TRUE
if(runInParallel){
  library("doParallel")
  registerDoParallel(cl = parallel::detectCores() - 1L)
}
Loading required package: foreach
foreach: simple, scalable parallel programming from Revolution Analytics
Use Revolution R for scalability, fault tolerance and more.
http://www.revolutionanalytics.com
Loading required package: iterators
Loading required package: parallel
preds <- subset_samples(phy_phy, Location == 'cecal') %>% 
    otu_table() %>% 
    t() %>% 
    as.matrix()
resp <- subset_samples(phy_phy, Location == 'cecal') %>% 
    sample_data() %>% 
    .[["Treatment"]] %>% 
    str_replace_all("^(?!C).*$", "Antibiotic") %>% 
    str_replace_all("^C", "Control")
resp
 [1] "Control"    "Control"    "Control"    "Control"    "Control"    "Control"    "Control"    "Control"    "Control"    "Control"   
[11] "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic"
[21] "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic"
[31] "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic"
[41] "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic" "Antibiotic"
sample_df <- data.frame(sample_data(phy_phy))
head(sample_df)
          X.SampleID BarcodeSequence LinkerPrimerSequence Treatment Location         Description
cecal_C1    cecal_C1              NA                   NA         C    cecal missing_description
cecal_C10  cecal_C10              NA                   NA         C    cecal missing_description
cecal_C2    cecal_C2              NA                   NA         C    cecal missing_description
cecal_C3    cecal_C3              NA                   NA         C    cecal missing_description
cecal_C4    cecal_C4              NA                   NA         C    cecal missing_description
cecal_C5    cecal_C5              NA                   NA         C    cecal missing_description
fitControl <- trainControl(## 10-fold CV
                           method = "repeatedcv",
                           number = 10,
                           classProbs = TRUE,
                           ## repeated ten times
                           repeats = 10,
                           summaryFunction = twoClassSummary,
                           allowParallel = runInParallel)
fit1svmL <- caret::train(x = as.matrix(t(otu_table(phy_phy))),
                         y = sample_df$Location, 
                         method = "svmLinear",
                         metric = "ROC",
                         trControl = fitControl,
                         verbose = FALSE)
fit1rf <- caret::train(x = as.matrix(t(otu_table(phy_phy))),
                       y = sample_df$Location, 
                       metric = "ROC",
                       method = "rf",
                       trControl = fitControl,
                       verbose = FALSE)
  1. Report mean, and the upper 95% confidence interval for AUC.
LS0tCnRpdGxlOiAiVVcgU3VtbWVyIEluc3RpdHV0ZXMgLSBJbnRyb2R1Y3Rpb24gdG8gTWV0YWdlbm9taWMgRGF0YSBBbmFseXNpcyAtIExhYiA3IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIFNldHVwCgpgYGB7ciBsb2FkX3BhY2thZ2VzfQpsaWJyYXJ5KHBoeWxvc2VxKQpsaWJyYXJ5KHZlZ2FuKQpsaWJyYXJ5KGFkZTQpCgpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2d0aGVtZXMpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeSh0aWR5cikKbGlicmFyeShkcGx5cikKYGBgCgpcICAKCjEuIExvYWQgdGhlIGltYWdlIGZvciBOYXR1cmUgNDg4LCBwcC4gNjIxLTYyNiBkYXRhc2V0LgoKYGBge3IgbG9hZF9kYXRhfQpsb2FkKCIuLi9kYXRhL1NUQVQucmRhdGEiKQpgYGAKClwgIAoKMi4gVXNlIGBkaXN0YW5jZSgpYCBmdW5jdGlvbiB0byBjb21wdXRlIEpTRCBkaXN0YW5jZSBvZiB0aGUgbm9ybWFsaXplZCBtaWNyb2Jpb21lCmRhdGEuCgpgYGB7ciBkaXN0X2pzZH0KZGlzdF9qc2QgPC0gcGh5bG9zZXE6OmRpc3RhbmNlKHBoeSwgbWV0aG9kID0gZGlzdGFuY2VNZXRob2RMaXN0JEpTRCkKc3RyKGRpc3RfanNkKQpgYGAKCjMuIENvbXB1dGUgaGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcgdXNpbmcgU2luZ2xlLCBBdmVyYWdlLCBhbmQgQ29tcGxldGUgbGlua2FnZS4KCmBgYHtyIGhjbHVzdF9zaW5nbGUsIGZpZy5oZWlnaHQ9Nn0KcGxvdChoY2x1c3QoZGlzdF9qc2QsICJzaW5nbGUiKSkKYGBgCgpgYGB7ciBoY2x1c3RfYXZlcmFnZSwgZmlnLmhlaWdodD02fQpoY2x1c3QoZGlzdF9qc2QsICJhdmVyYWdlIikgJT4lIAogICAgcGxvdCgpCmBgYAoKYGBge3IgaGNsdXN0X2NvbXBsZXRlLCBmaWcuaGVpZ2h0PTZ9CmhjbHVzdChkaXN0X2pzZCwgImNvbXBsZXRlIikgJT4lIAogICAgcGxvdCgpCmBgYAoKCjQuIFBsb3QgdGhlIGRlbmRyb2dyYW1zIGZyb20gKiozKiouCgoKNS4gVXNlIGByZWN0LmhjbHVzdGAgZnVuY3Rpb24gdG8gcHJvZHVjZSBiZXN0IGRpc2NyZXRlIGNsdXN0ZXJzIGZyb20gdGhlIGRlbmRyb2dyYW1zLgoKYGBge3IgcmVjdC5oY2x1c3Rfc2luZ2xlLCBmaWcuaGVpZ2h0PTZ9CmhjbHVzdF9zaW5nbGUgPSBoY2x1c3QoZGlzdF9qc2QsICJzaW5nbGUiKQpwbG90KGhjbHVzdF9zaW5nbGUpCnJlY3QuaGNsdXN0KGhjbHVzdF9zaW5nbGUsIGsgPSAzKQpgYGAKCgpgYGB7ciByZWN0LmhjbHVzdF9hdmVyYWdlLCBmaWcuaGVpZ2h0PTZ9CmhjbHVzdF9hdmVyYWdlID0gaGNsdXN0KGRpc3RfanNkLCAiYXZlcmFnZSIpCnBsb3QoaGNsdXN0X2F2ZXJhZ2UpCnJlY3QuaGNsdXN0KGhjbHVzdF9hdmVyYWdlLCBrID0gMykKYGBgCgpgYGB7ciByZWN0LmhjbHVzdF9jb21wbGV0ZSwgZmlnLmhlaWdodD02fQpoY2x1c3RfY29tcGxldGUgPSBoY2x1c3QoZGlzdF9qc2QsICJjb21wbGV0ZSIpCnBsb3QoaGNsdXN0X2NvbXBsZXRlKQpyZWN0LmhjbHVzdChoY2x1c3RfY29tcGxldGUsIGsgPSAzKQpgYGAKCjYuIENvbXB1dGUgYW5kIHBsb3QgY29waGVuZXRpYyBkaXN0YW5jZSBhZ2FpbnN0IHRoZSBKU0QgZGlzdGFuY2VzIGNvbXB1dGVkIGluICoqMioqCmZvciBlYWNoIG9mIHRoZSBoaWVyYXJjaGljYWwgY2x1c3RlcmluZ3MgaW4gKiozKiouCgpgYGB7ciBjb3BoZW5ldGljX3NpbmdsZX0KcGxvdChkaXN0X2pzZCwgY29waGVuZXRpYyhoY2x1c3Rfc2luZ2xlKSkKYGBgCgpgYGB7ciBjb3BoZW5ldGljX2F2ZXJhZ2V9CnBsb3QoZGlzdF9qc2QsIGNvcGhlbmV0aWMoaGNsdXN0X2F2ZXJhZ2UpKQpgYGAKCmBgYHtyIGNvcGhlbmV0aWNfY29tcGxldGV9CnBsb3QoZGlzdF9qc2QsIGNvcGhlbmV0aWMoaGNsdXN0X2NvbXBsZXRlKSkKYGBgCgo3LiBIb3cgd2VsbCBkbyB0aGUgY29waGVuZXRpYyBkaXN0YW5jZXMgcmVwcmVzZW50IHRoZSBvcmlnaW5hbCBkaXN0YW5jZXM/IENvbXB1dGUKY29ycmVsYXRpb25zLgoKCjguIFVzZSBQYXJ0aXRpb25pbmcgYXJvdW5kIE1lZG9pZHMsIGBwYW1gLCB0byBjbHVzdGVyIHRoZSBKU0QgZGlzdGFuY2VzIGludG8gdHdvIGNsdXN0ZXJzLgoKYGBge3IgcGFtX2pzZH0KcGFtX2pzZCA8LSBjbHVzdGVyOjpwYW0oZGlzdF9qc2QsIDIpCnN0cihwYW1fanNkKQojIHBsb3QocGFtX2pzZCkKYGBgCgo5LiBUZXN0IGZvciBhc3NvY2lhdGlvbiBvZiB0aGUgY2x1c3RlcnMgd2l0aCB0aGUgVHJlYXRtZW50IGFuZCBMb2NhdGlvbiBhbmQKdmFyaWFibGVzLgoKYGBge3J9CnRhYmxlKHNhbXBsZV9kYXRhKHBoeSkkVHJlYXRtZW50LCBwYW1fanNkJGNsdXN0ZXJpbmcpCmBgYAoKYGBge3J9CnRhYmxlKHNhbXBsZV9kYXRhKHBoeSkkTG9jYXRpb24sIHBhbV9qc2QkY2x1c3RlcmluZykKYGBgCgpgYGB7cn0KbGlicmFyeShjbHVzdGVyU2ltKQoKY2x1c3Rlci50ciA9IHRhYmxlKHNhbXBsZV9kYXRhKHBoeSkkVHJlYXRtZW50LCBwYW1fanNkJGNsdXN0ZXJpbmcpCmNoaXNxLnRlc3QoY2x1c3Rlci50cikKYGBgCgpgYGB7cn0KY2x1c3Rlci5sb2MgPSB0YWJsZShzYW1wbGVfZGF0YShwaHkpJExvY2F0aW9uLCBwYW1fanNkJGNsdXN0ZXJpbmcpCmNoaXNxLnRlc3QoY2x1c3Rlci5sb2MpCmBgYAoKCjEwLiBDb21wdXRlIHRoZSBnYXAgc3RhdGlzdGljIHBsb3QgdG8gZGV0ZXJtaW5lIHRoZSBvcHRpbWFsIG51bWJlciBvZiBjbHVzdGVycyBmb3IKdGhlc2UgZGF0YS4KCmBgYHtyfQpwYW0xIDwtIGZ1bmN0aW9uKHgsaykgbGlzdChjbHVzdGVyID0gcGFtKGFzLmRpc3QoeCksaywgY2x1c3Rlci5vbmx5PVRSVUUpKQpnc1BhbTEgPC0gY2x1c0dhcChhcy5tYXRyaXgoZGlzdF9qc2QpLCBGVU4gPSBwYW0xLCBLLm1heCA9IDIwLCBCID0gMTAwKQpgYGAKCmBgYHtyfQpwYXIobWZyb3c9YygxLDEpKQpwbG90KGdzUGFtMSkKYGBgCgpgYGB7cn0KZ3NQYW0xJFRhYiAlPiUgCiAgICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogICAgZ2dwbG90KGFlcyh4ID0gMToyMCwgeSA9IGdhcCkpICsKICAgIGdlb21fbGluZSgpICsKICAgIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBnYXAgLSAyKlNFLnNpbSwgeW1heCA9IGdhcCArIDIqU0Uuc2ltKSwgCiAgICAgICAgICAgICAgICAgIGNvbG91ciA9ICJyZWQiKSArCiAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gZ2FwIC0gU0Uuc2ltLCB5bWF4ID0gZ2FwICsgU0Uuc2ltKSwgCiAgICAgICAgICAgICAgICAgIGNvbG91ciA9ICJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpCmBgYAoKCjExLiBJbnN0YWxsIGFuZCBsb2FkIHRoZSBmb2xsb3dpbmcgcGFja2FnZXM6ICJyYW5kb21Gb3Jlc3QiLCAia2VybmxhYiIsICJST0NSIi4KCgoxMi4gVXNlIHRoZSBwcm92aWRlZCA2LWZvbGQgY3Jvc3MgdmFsaWRhdGlvbiBmdW5jdGlvbnMKKGBzdm0ua2ZvbGRBVUNgIGFuZCBgcmYua2ZvbGRBVUNgKQp0byBlc3RpbWF0ZSBwcmVkaWN0aW9uIGFjY3VyYWN5IGluIDEwMCByZXBldGl0aW9ucyB1c2luZyBQaHlsdW0gbGV2ZWwgZGF0YSBmb3I6CgpBLiBMb2NhdGlvbjsKQi4gQW50aWJpb3RpYyB2cy4gQ29udHJvbCB3aXRoaW4gZmVjYWwgc2FtcGxlczsKQy4gQW50aWJpb3RpYyB2cy4gQ29udHJvbCB3aXRoaW4gY2VjYWwgc2FtcGxlcy4KCkFsdGVybmF0aXZlbHksIHVzZSB0aGUgImNhcmV0IiBwYWNrYWdlIHRvIGFjY29tcGxpc2ggdGhlIHNhbWUuCgpgYGB7cn0Kc291cmNlKCIuLi9sYWJzL0xhYi0wNy1DbHVzdGVyaW5nLWFuZC1DbGFzc2lmaWNhdGlvbi9DVl9wcm90b2NvbHMuUiIpCmBgYAoKCmBgYHtyIHBoeV9waHl9CnBoeV9waHkgPC0gdGF4X2dsb20ocGh5LCB0YXhyYW5rID0gIlBoeWx1bSIpCmBgYAoKYGBge3J9CnJ1bkluUGFyYWxsZWwgPSBUUlVFCmlmKHJ1bkluUGFyYWxsZWwpewogIGxpYnJhcnkoImRvUGFyYWxsZWwiKQogIHJlZ2lzdGVyRG9QYXJhbGxlbChjbCA9IHBhcmFsbGVsOjpkZXRlY3RDb3JlcygpIC0gMUwpCn0KCmBgYAoKYGBge3J9CnByZWRzIDwtIHN1YnNldF9zYW1wbGVzKHBoeV9waHksIExvY2F0aW9uID09ICdjZWNhbCcpICU+JSAKICAgIG90dV90YWJsZSgpICU+JSAKICAgIHQoKSAlPiUgCiAgICBhcy5tYXRyaXgoKQoKcmVzcCA8LSBzdWJzZXRfc2FtcGxlcyhwaHlfcGh5LCBMb2NhdGlvbiA9PSAnY2VjYWwnKSAlPiUgCiAgICBzYW1wbGVfZGF0YSgpICU+JSAKICAgIC5bWyJUcmVhdG1lbnQiXV0gJT4lIAogICAgc3RyX3JlcGxhY2VfYWxsKCJeKD8hQykuKiQiLCAiQW50aWJpb3RpYyIpICU+JSAKICAgIHN0cl9yZXBsYWNlX2FsbCgiXkMiLCAiQ29udHJvbCIpCnJlc3AKYGBgCgpgYGB7ciBsb2Nfc3ZtfQpzYW1wbGVfZGYgPC0gZGF0YS5mcmFtZShzYW1wbGVfZGF0YShwaHlfcGh5KSkKaGVhZChzYW1wbGVfZGYpCmBgYAoKYGBge3J9CmZpdENvbnRyb2wgPC0gdHJhaW5Db250cm9sKCMjIDEwLWZvbGQgQ1YKICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gInJlcGVhdGVkY3YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBudW1iZXIgPSAxMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3NQcm9icyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICMjIHJlcGVhdGVkIHRlbiB0aW1lcwogICAgICAgICAgICAgICAgICAgICAgICAgICByZXBlYXRzID0gMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcnlGdW5jdGlvbiA9IHR3b0NsYXNzU3VtbWFyeSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxsb3dQYXJhbGxlbCA9IHJ1bkluUGFyYWxsZWwpCgpgYGAKCmBgYHtyfQpmaXQxc3ZtTCA8LSBjYXJldDo6dHJhaW4oeCA9IGFzLm1hdHJpeCh0KG90dV90YWJsZShwaHlfcGh5KSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHNhbXBsZV9kZiRMb2NhdGlvbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAic3ZtTGluZWFyIiwKICAgICAgICAgICAgICAgICAgICAgICAgIG1ldHJpYyA9ICJST0MiLAogICAgICAgICAgICAgICAgICAgICAgICAgdHJDb250cm9sID0gZml0Q29udHJvbCwKICAgICAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2UgPSBGQUxTRSkKCmBgYAoKYGBge3J9CmZpdDFyZiA8LSBjYXJldDo6dHJhaW4oeCA9IGFzLm1hdHJpeCh0KG90dV90YWJsZShwaHlfcGh5KSkpLAogICAgICAgICAgICAgICAgICAgICAgIHkgPSBzYW1wbGVfZGYkTG9jYXRpb24sIAogICAgICAgICAgICAgICAgICAgICAgIG1ldHJpYyA9ICJST0MiLAogICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJyZiIsCiAgICAgICAgICAgICAgICAgICAgICAgdHJDb250cm9sID0gZml0Q29udHJvbCwKICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gRkFMU0UpCgpgYGAKCgoxMy4gUmVwb3J0IG1lYW4sIGFuZCB0aGUgdXBwZXIgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgZm9yIEFVQy4K